/*
 * MainDictionaryTopComponentN.java
 *
 * Created on Utorok, 2008, január 8, 0:23
 */
package eu.easyedu.dictionary.gui;

import eu.easyedu.dictionary.api.model.Dictionary;
import eu.easyedu.dictionary.api.model.Language;
import eu.easyedu.dictionary.api.model.Word;
import eu.easyedu.dictionary.api.model.WordRelationship;
import eu.easyedu.dictionary.api.model.WordType;
import eu.easyedu.dictionary.api.nservice.spi.AsynchronousSearch;
import eu.easyedu.dictionary.api.nservice.spi.WordBookService;
import eu.easyedu.dictionary.api.service.events.CreateEntityDictionaryEvent;
import eu.easyedu.dictionary.api.service.events.SearchEvent;
import eu.easyedu.dictionary.api.service.events.SearchEventListener;
import eu.easyedu.dictionary.api.service.events.SearchResultEvent;
import eu.easyedu.dictionary.api.service.events.WordBookEventListener;
import eu.easyedu.dictionary.api.util.ConnectionDoesNotExistsException;
import eu.easyedu.dictionary.api.util.ConnectionEvent;
import eu.easyedu.dictionary.api.util.ConnectionEventListener;
import eu.easyedu.dictionary.api.util.DatabaseUtils;
import eu.easyedu.dictionary.api.util.DictionaryConnection;
import eu.easyedu.dictionary.gui.resources.Bundle;
import java.awt.Frame;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.ListSelectionModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import org.openide.util.Exceptions;
import org.openide.util.ImageUtilities;
import org.openide.util.Lookup;
import org.openide.util.LookupEvent;
import org.openide.util.LookupListener;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
import org.openide.util.Utilities;
import org.openide.util.lookup.Lookups;

/**
 *
 * @author  hlavki
 */
public class MainDictionaryTopComponent extends TopComponent implements ConnectionEventListener,
        WordBookEventListener, SearchEventListener, LookupListener {

    private static final long serialVersionUID = 1L;
    private static final Logger log = Logger.getLogger(MainDictionaryTopComponent.class.getName());
    private static MainDictionaryTopComponent instance;
    /** path to the icon used by the component and its open action */
    static final String ICON_PATH = Bundle.getResourcesPath() + "/dictionary16x16.png";
    private static final String PREFERRED_ID = "MainDictionaryTopComponent";
    private static String[] RESULT_TABLE_COLUMN_NAMES = new String[]{
        Bundle.getMessage("MainDictionaryTopComponent.table.word"),
        Bundle.getMessage("MainDictionaryTopComponent.table.relationship"),
        Bundle.getMessage("MainDictionaryTopComponent.table.language")
    };
    private Dictionary dictionary;
    private PropertyChangeListener optionsListener;
    private Lookup.Result<Dictionary> result = null;
    private AsynchronousSearch search;
    private WordBookService wbService;

    /** Creates new form MainDictionaryTopComponentN */
    private MainDictionaryTopComponent(Dictionary dictionary) {
        initComponents();
        resultTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        setName(Bundle.getMessage("CTL_MainDictionaryTopComponent", dictionary.getName()));
        setToolTipText(Bundle.getMessage("HINT_MainDictionaryTopComponent"));
        setIcon(ImageUtilities.loadImage(ICON_PATH, true));
//        DictionaryOptions opts = DictionaryOptions.getInstance();
        this.dictionary = dictionary;
        this.search = new AsynchronousSearch(dictionary);
        this.wbService = Lookup.getDefault().lookup(WordBookService.class);

//        try {
//            dictionary = new Dictionary("dictionary", opts.getPreferredLanguage());
//        } catch (ConnectionDoesNotExistsException e) {
//            setVisible(false);
//        }
        associateLookup(Lookups.singleton(dictionary));
//        DictionaryPersistenceProvider persistence = Lookup.getDefault().lookup(DictionaryPersistenceProvider.class);
//        try {
//            persistence.setConnection(DatabaseUtils.getConnection(dictionary.getConnectionName()));
//            if (persistence.isConnected()) {
//                setConnected();
//            } else {
//                setDisconnected();
//            }
//        } catch (ConnectionDoesNotExistsException ex) {
//            Exceptions.printStackTrace(ex);
//        }
        optionsListener = new OptionsPropertyChangeListener();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        toolBar = new javax.swing.JToolBar();
        addWordButton = new javax.swing.JButton();
        addLanguageButton = new javax.swing.JButton();
        connectButton = new javax.swing.JButton();
        languageComboBox = new javax.swing.JComboBox();
        searchTextField = new javax.swing.JTextField();
        searchLabel = new javax.swing.JLabel();
        resultSplitPane = new javax.swing.JSplitPane();
        wordListScrollPane = new javax.swing.JScrollPane();
        wordList = new javax.swing.JList();
        resultTableScrollPane = new javax.swing.JScrollPane();
        resultTable = new javax.swing.JTable();

        toolBar.setRollover(true);

        addWordButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/eu/easyedu/dictionary/gui/resources/icons/new-word.png"))); // NOI18N
        addWordButton.setFocusable(false);
        addWordButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        addWordButton.setMaximumSize(new java.awt.Dimension(32, 32));
        addWordButton.setMinimumSize(new java.awt.Dimension(32, 32));
        addWordButton.setPreferredSize(new java.awt.Dimension(32, 32));
        addWordButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        addWordButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addWordButtonActionPerformed(evt);
            }
        });
        toolBar.add(addWordButton);

        addLanguageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/eu/easyedu/dictionary/gui/resources/icons/new-language.png"))); // NOI18N
        addLanguageButton.setFocusable(false);
        addLanguageButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        addLanguageButton.setMaximumSize(new java.awt.Dimension(32, 32));
        addLanguageButton.setMinimumSize(new java.awt.Dimension(32, 32));
        addLanguageButton.setPreferredSize(new java.awt.Dimension(32, 32));
        addLanguageButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        addLanguageButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addLanguageButtonActionPerformed(evt);
            }
        });
        toolBar.add(addLanguageButton);

        connectButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/eu/easyedu/dictionary/gui/resources/icons/connect.png"))); // NOI18N
        connectButton.setFocusable(false);
        connectButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        connectButton.setMaximumSize(new java.awt.Dimension(32, 32));
        connectButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        connectButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                connectButtonActionPerformed(evt);
            }
        });
        toolBar.add(connectButton);

        languageComboBox.setMaximumSize(new java.awt.Dimension(150, 32767));
        languageComboBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                languageComboBoxActionPerformed(evt);
            }
        });
        toolBar.add(languageComboBox);

        searchTextField.setBackground(new java.awt.Color(217, 217, 246));
        searchTextField.setFont(new java.awt.Font("SansSerif", 1, 14));
        searchTextField.addCaretListener(new javax.swing.event.CaretListener() {
            public void caretUpdate(javax.swing.event.CaretEvent evt) {
                searchTextFieldCaretUpdate(evt);
            }
        });
        searchTextField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                searchTextFieldActionPerformed(evt);
            }
        });

        searchLabel.setText(Bundle.getMessage("MainDictionaryTopComponent.searchLabel.text")); // NOI18N

        resultSplitPane.setDividerLocation(170);

        wordList.setModel(new DefaultListModel());
        wordList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                wordListValueChanged(evt);
            }
        });
        wordListScrollPane.setViewportView(wordList);

        resultSplitPane.setLeftComponent(wordListScrollPane);

        resultTable.setModel(getTranslationTableModel());
        resultTable.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                resultTableMouseClicked(evt);
            }
        });
        resultTableScrollPane.setViewportView(resultTable);

        resultSplitPane.setRightComponent(resultTableScrollPane);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(searchLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 85, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(searchTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 495, Short.MAX_VALUE))
                    .addGroup(layout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(resultSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 592, Short.MAX_VALUE))
                    .addComponent(toolBar, javax.swing.GroupLayout.DEFAULT_SIZE, 604, Short.MAX_VALUE))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(toolBar, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(searchLabel)
                    .addComponent(searchTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(resultSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 209, Short.MAX_VALUE)
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents
    private void addWordButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addWordButtonActionPerformed
        Word selectedWord = (Word) wordList.getSelectedValue();
        boolean wordExists = selectedWord != null;
        Word initialWord = wordExists ? selectedWord : new Word(searchTextField.getText(), getSelectedLanguage());
        if (!wordExists) {
            initialWord.setType(WordType.UNKNOWN);
        }
//        Frame mainWindow = WindowManager.getDefault().getMainWindow();
//        AddWordDialog dialog = new AddWordDialog(mainWindow, true, initialWord, dictionary, wordExists);
//        dialog.setLocationRelativeTo(mainWindow);
//        dialog.setVisible(true);
//        dictionary.setLanguage(dialog.getWord().getLanguage());
//        searchTextField.setText(dialog.getWord().getWord());
        Frame mainWindow = WindowManager.getDefault().getMainWindow();
        AddRelationDialog dialog = new AddRelationDialog(mainWindow, true, dictionary, initialWord);
        dialog.setLocationRelativeTo(mainWindow);
        dialog.setVisible(true);
        performSearch();
    }//GEN-LAST:event_addWordButtonActionPerformed

    private void connectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_connectButtonActionPerformed
        try {
            DictionaryConnection conn = DatabaseUtils.getConnection(dictionary);
            if (conn.isConnected()) {
                conn.disconnect();
            } else {
                conn.connect();
            }
        } catch (ConnectionDoesNotExistsException ex) {
            Exceptions.printStackTrace(ex);
        }
    }//GEN-LAST:event_connectButtonActionPerformed

    private void languageComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_languageComboBoxActionPerformed
        performSearch();
    }//GEN-LAST:event_languageComboBoxActionPerformed

    private void searchTextFieldCaretUpdate(javax.swing.event.CaretEvent evt) {//GEN-FIRST:event_searchTextFieldCaretUpdate
        performSearch();
    }//GEN-LAST:event_searchTextFieldCaretUpdate

    private void wordListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_wordListValueChanged
        if (evt.getValueIsAdjusting() == false) {
            Word word = (Word) wordList.getSelectedValue();
            if (word != null) {
                List<WordRelationship> words = wbService.getAllRelatedWords(dictionary, word);
                setTranslationTableModel(words);
            }
        }
    }//GEN-LAST:event_wordListValueChanged

    private void addLanguageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addLanguageButtonActionPerformed
        Frame mainWindow = WindowManager.getDefault().getMainWindow();
        AddLanguageDialog dialog = new AddLanguageDialog(mainWindow, true, dictionary);
        dialog.setLocationRelativeTo(mainWindow);
        dialog.setVisible(true);
        languageComboBox.setSelectedItem(dialog.getLanguage());
}//GEN-LAST:event_addLanguageButtonActionPerformed

    private void resultTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_resultTableMouseClicked
        int selectedRow = resultTable.getSelectedRow();
        if (evt.getClickCount() == 2 && selectedRow > -1) {
            languageComboBox.setSelectedItem(resultTable.getModel().getValueAt(selectedRow, 2));
            searchTextField.setText((String) resultTable.getModel().getValueAt(selectedRow, 0));
            performSearch();
        }
    }//GEN-LAST:event_resultTableMouseClicked

    private void searchTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchTextFieldActionPerformed
        performSearch();
    }//GEN-LAST:event_searchTextFieldActionPerformed
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton addLanguageButton;
    private javax.swing.JButton addWordButton;
    private javax.swing.JButton connectButton;
    private javax.swing.JComboBox languageComboBox;
    private javax.swing.JSplitPane resultSplitPane;
    private javax.swing.JTable resultTable;
    private javax.swing.JScrollPane resultTableScrollPane;
    private javax.swing.JLabel searchLabel;
    private javax.swing.JTextField searchTextField;
    private javax.swing.JToolBar toolBar;
    private javax.swing.JList wordList;
    private javax.swing.JScrollPane wordListScrollPane;
    // End of variables declaration//GEN-END:variables

    /**
     * Gets default instance. Do not use directly: reserved for *.settings files only,
     * i.e. deserialization routines; otherwise you could get a non-deserialized instance.
     * To obtain the singleton instance, use {@link findInstance}.
     */
    public static synchronized MainDictionaryTopComponent getDefault(Dictionary dictionary) {
        if (instance == null) {
            instance = new MainDictionaryTopComponent(dictionary);
        }
        return instance;
    }

    public TableModel getTranslationTableModel() {
        TableModel model = new DefaultTableModel(RESULT_TABLE_COLUMN_NAMES, 0) {

            private static final long serialVersionUID = 1L;

            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        };
        return model;
    }

    protected final void setTranslationTableModel(List<WordRelationship> words) {
        Object[][] data = new Object[words.size()][3];
        resultTable.getColumnModel().getColumn(1).setWidth(100);
        int idx = 0;
        for (WordRelationship rel : words) {
            data[idx][0] = rel.getRelatedWord().getWord();
            data[idx][1] = rel.getRelationship();
            data[idx][2] = rel.getRelatedWord().getLanguage();
            idx++;
        }
        DefaultTableModel model = (DefaultTableModel) resultTable.getModel();
        model.setDataVector(data, RESULT_TABLE_COLUMN_NAMES);
    }

    protected final void clearResultTable() {
        DefaultTableModel model = (DefaultTableModel) resultTable.getModel();
        model.setRowCount(0);
    }

    /**
     * Obtain the MainDictionaryTopComponent instance. Never call {@link #getDefault} directly!
     */
    public static synchronized MainDictionaryTopComponent findInstance(Dictionary dictionary) {
// TODO: remove - old version
//        TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID);
//        if (win == null) {
//            Logger.getLogger(MainDictionaryTopComponent.class.getName()).warning(
//                    "Cannot find " + PREFERRED_ID +
//                    " component. It will not be located properly in the window system.");
//            return getDefault();
//        }
//        if (win instanceof MainDictionaryTopComponent) {
//            return (MainDictionaryTopComponent) win;
//        }
//        Logger.getLogger(MainDictionaryTopComponent.class.getName()).warning(
//                "There seem to be multiple components with the '" + PREFERRED_ID +
//                "' ID. That is a potential source of errors and unexpected behavior.");
//        return getDefault();

// FIXME: toto je nova verzia, ktora bude aktualna az po nasadeni nodov        
        Iterator<TopComponent> it = TopComponent.getRegistry().getOpened().iterator();
        while (it.hasNext()) {
            TopComponent c = it.next();
            if (c instanceof MainDictionaryTopComponent) {
                MainDictionaryTopComponent dtc = (MainDictionaryTopComponent) c;
                if (dictionary.equals(dtc.getDictionary())) {
                    return dtc;
                }
            }
        }
        return new MainDictionaryTopComponent(dictionary);
    }

    public
    @Override
    int getPersistenceType() {
        return TopComponent.PERSISTENCE_NEVER;
    }

    public
    @Override
    void componentOpened() {
        Lookup.Template<Dictionary> tpl = new Lookup.Template<Dictionary>(Dictionary.class);
        result = Utilities.actionsGlobalContext().lookup(tpl);
        result.addLookupListener(this);
        DatabaseUtils.addConnectionEventListener(dictionary, this);
        dictionary.addPropertyChangeListener(optionsListener);
        dictionary.addWordBookEventListener(this);
        search.addSearchEventListener(this);
        try {
            if (DatabaseUtils.getConnection(dictionary).isConnected()) {
                setConnected();
            } else {
                setDisconnected();
            }
        } catch (ConnectionDoesNotExistsException e) {
            Exceptions.printStackTrace(e);
        }
    }

    public
    @Override
    void componentClosed() {
        DatabaseUtils.removeConnectionEventListener(dictionary, this);
        dictionary.removePropertyChangeListener(optionsListener);
        dictionary.removeWordBookEventListener(this);
        search.removeSearchEventListener(this);
    }

    @Override
    protected void componentActivated() {
        super.componentActivated();
    }

    /** replaces this in object stream */
    public
    @Override
    Object writeReplace() {
        return new ResolvableHelper(dictionary);
    }

    protected
    @Override
    String preferredID() {
        return PREFERRED_ID;
    }

    public void connect(ConnectionEvent evt) {
        setConnected();
    }

    private void setConnected() {
        log.info("Setting icon to disconnect");
        connectButton.setIcon(new javax.swing.ImageIcon(Bundle.getClasspathResource("icons/disconnect.png")));
        languageComboBox.setEnabled(true);
        refreshLanguageComboBox(null);
//        DictionaryOptions opts = DictionaryOptions.getInstance();
//        if (opts.isUnsetLanguage()) {
//            dictionary.setLanguage((Language) languageComboBox.getItemAt(0));
//        }
    }

    public void refreshLanguageComboBox(Language selectedItem) {
        DefaultComboBoxModel model = (DefaultComboBoxModel) languageComboBox.getModel();
        model.removeAllElements();
        for (Language language : wbService.getAllLanguages(dictionary)) {
            model.addElement(language);
        }
        if (selectedItem != null) {
            languageComboBox.setSelectedItem(selectedItem);
        }
    }

    public void disconnect(ConnectionEvent evt) {
        setDisconnected();
    }

    private void setDisconnected() {
        log.info("Setting icon to connect");
        connectButton.setIcon(new javax.swing.ImageIcon(Bundle.getClasspathResource("icons/connect.png")));
        languageComboBox.setModel(new DefaultComboBoxModel());
        languageComboBox.setEnabled(false);
    }

    final static class ResolvableHelper implements Serializable {

        private static final long serialVersionUID = 1L;
        private Dictionary dictionary;

        public ResolvableHelper(Dictionary dictionary) {
            this.dictionary = dictionary;
        }

        public Object readResolve() {
            return MainDictionaryTopComponent.getDefault(dictionary);
        }
    }

    final private class OptionsPropertyChangeListener implements PropertyChangeListener {

        public void propertyChange(PropertyChangeEvent evt) {
            if ("language".equals(evt.getPropertyName())) {
                if (languageComboBox.isEnabled()) {
                    languageComboBox.setSelectedItem(evt.getNewValue());
                }
            }
        }
    }

    public void addWord(CreateEntityDictionaryEvent<Word> evt) {
        // do nothing for now
    }

    public void addLanguage(CreateEntityDictionaryEvent<Language> evt) {
        refreshLanguageComboBox(evt.getCreatedObject());
    }

    public void searchStarted(SearchEvent evt) {
        log.info("Search started with word " + evt.getSearchString());
        clearResultTable();
        wordList.setListData(new Object[]{});
    }

    public void searchStopped(SearchResultEvent evt) {
        List<Word> searchResult = evt.getSearchResult();
        wordList.setListData(searchResult.toArray(searchResult.toArray()));
        if (searchResult.size() > 0) {
            wordList.setSelectedIndex(0);
        }
    }

    public void resultChanged(LookupEvent lookupEvent) {
        @SuppressWarnings("unchecked")
        Lookup.Result<Dictionary> r = (Lookup.Result<Dictionary>) lookupEvent.getSource();
        Collection<? extends Dictionary> c = r.allInstances();
        if (!c.isEmpty()) {
            Dictionary o = (Dictionary) c.iterator().next();
            // TODO do nothing for now
        } else {
            // TODO do nothing for now
        }
    }

    private Language getSelectedLanguage() {
        return (Language) languageComboBox.getSelectedItem();
    }

    protected Dictionary getDictionary() {
        return dictionary;
    }

    public void dictionaryChanged() {
        System.out.println("DICTIONARY CHANGED");
    }

    private void performSearch() {
        if (searchTextField.getText().length() > 2) {
            search.search(searchTextField.getText(), getSelectedLanguage());
        }
    }
}

